#include <format>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>



export template <typename T, size_t WIDTH = 10, size_t HEIGHT = 10>   //
class Grid
{
public:
    Grid()                           = default;
    virtual ~Grid()                  = default;

    // 显式默认复制构造函数和赋值操作符
    Grid(const Grid& src)            = default;
    Grid& operator=(const Grid& rhs) = default;

    template <typename E, size_t WIDTH2, size_t HEIGHT2>   //
    Grid(const Grid<E, WIDTH2, HEIGHT2>& src);

    template <typename E, size_t WIDTH2, size_t HEIGHT2>   //
    Grid& operator=(const Grid<E, WIDTH2, HEIGHT2>& rhs);

    void swap(Grid& other) noexcept;

    std::optional<T>&       at(size_t x, size_t y);
    const std::optional<T>& at(size_t x, size_t y) const;

    size_t getHeight() const { return HEIGHT };
    size_t getWidth() const { return WIDTH };

private:
    void verifyCoordinate(size_t x, size_t y) const;

    std::optional<T> m_cells[WIDTH][HEIGHT];
};


template <typename T, size_t WIDTH, size_t HEIGHT>
template <typename E, size_t WIDTH2, size_t HEIGHT2>
Grid<T, WIDTH, HEIGHT>::Grid(const Grid<E, WIDTH2, HEIGHT2>& src)
{
    for (size_t i{0}; i < WIDTH; i++)
    {
        for (size_t j{0}; j < HEIGHT; j++)
        {
            if (i < WIDTH2 && j < HEIGHT2)
            {
                m_cells[i][j] = src.at(i, j);
            }
            else
            {
                m_cells[i][j].reset();
            }
        }
    }
}


template <typename T, size_t WIDTH, size_t HEIGHT>
void Grid<T, WIDTH, HEIGHT>::swap(Grid& other) noexcept
{
    std::swap(m_cells, other.m_cells);
}

template <typename T, size_t WIDTH, size_t HEIGHT>
template <typename E, size_t WIDTH2, size_t HEIGHT2>
Grid<T, WIDTH, HEIGHT>& Grid<T, WIDTH, HEIGHT>::operator=(   //
    const Grid<E, WIDTH2, HEIGHT2>& rhs)
{
    // 复制和交换惯用手法
    Grid<T, WIDTH, HEIGHT> temp(rhs);   // 在临时实例中完成所有工作。
    swap(temp);                         // 只使用非抛出操作提交工作。
    return *this;
}


export module grid:string;
// 当使用模板专门化时，原始模板也必须是可见的。
import :main;

export template <>   //
class Grid<const char*>
{
public:
    explicit Grid(size_t width  = DefaultWidth,   //
                  size_t height = DefaultHeight);
    virtual ~Grid()                  = default;

    // 显式默认复制构造函数和赋值操作符。
    Grid(const Grid& src)            = default;
    Grid& operator=(const Grid& rhs) = default;

    // 显式默认移动构造函数和赋值操作符。
    Grid(Grid& src)                  = default;
    Grid& operator=(Grid& rhs)       = default;

    std::optional<std::string>&       at(size_t x, size_t y);
    const std::optional<std::string>& at(size_t x, size_t y) const;

    size_t getHeight() const;
    size_t getWidth() const;

    static const size_t DefaultWidth{10};
    static const size_t DefaultHeight{10};

private:
    void verifyCoordinate(size_t x, size_t y) const;

    std::vector<std::vector<std::optional<std::string>>>   //
           m_cells;
    size_t m_width{0}, m_height{0};
};

export module grid;
export import :main;
export import :string;

void test()
{
    Grid<int>         myIntGrid;
    Grid<const char*> stringGrid{2, 3};

    const char* dummy{"dummy"};
    stringGrid.at(0, 0) = "hello";
    stringGrid.at(0, 1) = dummy;
    stringGrid.at(1, 0) = dummy;
    stringGrid.at(1, 1) = "there";

    Grid<const char*> stringGrid2{stringGrid};
}

Grid<const char*>::Grid(size_t width, size_t height)
    : m_width{width},
      m_height{height}
{
    m_cells.resize(m_width);
    for (auto& column : m_cells)
    {
        column.resize(m_height);
    }
}

void Grid<const char*>::verifyCoordinate(size_t x, size_t y) const
{
    if (x >= m_width)
    {
        throw std::out_of_range   //
            {std::format("{} must be less than {}.", x, m_width)};
    }
    if (y >= m_height)
    {
        throw std::out_of_range   //
            {std::format("{} must be less than {}.", x, m_height)};
    }
}


const std::optional<std::string>&   //
Grid<const char*>::at(size_t x, size_t y) const
{
    verifyCoordinate(x, y);
    return m_cells[x][y];
}

std::optional<std::string>& Grid<const char*>::at(size_t x, size_t y)
{
    return const_cast<std::optional<std::string>&>   //
        (std::as_const(*this).at(x, y));
}
